#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "token.h"

static int id=0;

Token *createToken()
{
    Token *token;
    token=(Token*)calloc(sizeof(Token),1);
    return token;
}

Token *createLabelToken(SourceLocation *location)
{
    Token *token;
    token=createToken();
    token->type=TK_IDENTIFY;
    token->location.line=location->line;
    token->location.column=location->column;
    token->text=(char*)malloc(sizeof(char)*32);
    sprintf(token->text,"@auto%d",id);
    id++;
    return token;
}

void freeToken(Token *token)
{
    if(token){
        if(token->text)
            free(token->text);
         free(token);
    }
}

Token *initToken(Token *token,TokenType type,SourceLocation *location,char *text)
{
    assert(token);
    assert(location);
    token->type=type;
    token->text=text;
    token->location.line=location->line;
    token->location.column=location->column;
    return token;
}

Token *checkKeyToken(Token *token)
{
    assert(token);

    if(token->type==TK_IDENTIFY){
        if((strcmp(token->text,"do")==0)){
            token->type=TKKEY_DO;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"if")==0)){
            token->type=TKKEY_IF;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"else")==0)){
            token->type=TKKEY_ELSE;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"while")==0)){
            token->type=TKKEY_WHILE;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"for")==0)){
            token->type=TKKEY_FOR;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"return")==0)){
            token->type=TKKEY_RETURN;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"break")==0)){
            token->type=TKKEY_BREAK;
            free(token->text);
            token->text=0;
        }else if((strcmp(token->text,"continue")==0)){
            token->type=TKKEY_CONTINUE;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"true")==0){
            token->type=TKKEY_TRUE;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"false")==0){
            token->type=TKKEY_FALSE;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"namespace")==0){
            token->type=TKKEY_NAMESPACE;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"import")==0){
            token->type=TKKEY_IMPORT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"struct")==0){
            token->type=TKKEY_STRUCT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"enum")==0){
            token->type=TKKEY_ENUM;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"interface")==0){
            token->type=TKKEY_INTERFACE;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"new")==0){
            token->type=TKKEY_NEW;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"delete")==0){
            token->type=TKKEY_DELETE;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"null")==0){
            token->type=TKKEY_NULL;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"void")==0){
            token->type=TKKEY_VOID;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"bool")==0){
            token->type=TKKEY_BOOL;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"char")==0){
            token->type=TKKEY_CHAR;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"uchar")==0){
            token->type=TKKEY_UCHAR;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"short")==0){
            token->type=TKKEY_SHORT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"ushort")==0){
            token->type=TKKEY_USHORT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"int")==0){
            token->type=TKKEY_INT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"uint")==0){
            token->type=TKKEY_UINT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"long")==0){
            token->type=TKKEY_LONG;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"ulong")==0){
            token->type=TKKEY_ULONG;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"float")==0){
            token->type=TKKEY_FLOAT;
            free(token->text);
            token->text=0;
        }else if(strcmp(token->text,"double")==0){
            token->type=TKKEY_DOUBLE;
            free(token->text);
            token->text=0;
        }
    }
    return token;
}

static void printTextToken(Token *token,char *text)
{
    printf("%s\tline:%d\tcolumn:%d\t%s\n",text,token->location.line,token->location.column,token->text);

}

static void printPureToken(Token *token,char *text)
{
    printf("%s:\tline:%d\tcolumn:%d\n",text,token->location.line,token->location.column);
}

void printToken(Token *token)
{
    assert(token);
    switch(token->type){
        case TK_END:{
            printf("TK_END\n");
            break;
        }
        case TK_IDENTIFY:{
            printTextToken(token,"TK_IDENTIFY");
            break;
        }
        case TK_NUMBER:{
            printTextToken(token,"TK_NUMBER");
            break;
        }
        case TK_FLOAT:{
            printTextToken(token,"TK_FLOAT");
            break;
        }
        case TK_STRING:{
            printTextToken(token,"TK_STRING");
            break;
        }
        case TK_COMMENT:{
            printTextToken(token,"TK_COMMENT");
            break;
        }


                case TKOPT_INC:{
                    printPureToken(token,"TKOPT_INC");
                    break;
                }
        case TKOPT_DEC:{
            printPureToken(token,"TKOPT_DEC");
            break;
        }
        case TKOPT_ADD:{
            printPureToken(token,"TKOPT_ADD");
            break;
        }
        case TKOPT_SUB:{
            printPureToken(token,"TKOPT_SUB");
            break;
        }
        case TKOPT_MUL:{
            printPureToken(token,"TKOPT_MUL");
            break;
        }
        case TKOPT_DIV:{
            printPureToken(token,"TKOPT_DIV");
            break;
        }
        case TKOPT_MOD:{
            printPureToken(token,"TKOPT_MOD");
            break;
        }
        case TKOPT_ASSIGN:{
            printPureToken(token,"TKOPT_ASSIGN");
            break;
        }
        case TKOPT_ADDASSIGN:{
            printPureToken(token,"TKOPT_ADDASSIGN");
            break;
        }
        case TKOPT_SUBASSIGN:{
            printPureToken(token,"TKOPT_SUBASSIGN");
            break;
        }
        case TKOPT_MULASSIGN:{
            printPureToken(token,"TKOPT_MULASSIGN");
            break;
        }
        case TKOPT_DIVASSIGN:{
            printPureToken(token,"TKOPT_DIVASSIGN");
            break;
        }
        case TKOPT_MODASSIGN:{
            printPureToken(token,"TKOPT_MODASSIGN");
            break;
        }
            //bitopt
        case TKOPT_BITAND:{
            printPureToken(token,"TKOPT_BITAND");
            break;
        }
        case TKOPT_BITOR:{
            printPureToken(token,"TKOPT_BITOR");
            break;
        }
        case TKOPT_BITXOR:{
            printPureToken(token,"TKOPT_BITXOR");
            break;
        }
        case TKOPT_BITNOT:{
            printPureToken(token,"TKOPT_BITNOT");
            break;
        }
        case TKOPT_BITANDASSIGN:{
            printPureToken(token,"TKOPT_BITANDASSIGN");
            break;
        }
        case TKOPT_BITORASSIGN:{
            printPureToken(token,"TKOPT_BITORASSIGN");
            break;
        }
        case TKOPT_BITXORASSIGN:{
            printPureToken(token,"TKOPT_BITXORASSIGN");
            break;
        }
        //bool
        case TKOPT_AND:{
            printPureToken(token,"TKOPT_AND");
            break;
        }
        case TKOPT_OR:{
            printPureToken(token,"TKOPT_OR");
            break;
        }
        case TKOPT_NOT:{
            printPureToken(token,"TKOPT_NOT");
            break;
        }
        case TKOPT_ANDASSIGN:{
            printPureToken(token,"TKOPT_ANDASSIGN");
            break;
        }
        case TKOPT_ORASSIGN:{
            printPureToken(token,"TKOPT_ORASSIGN");
            break;
        }
		//bit shift
		case TKOPT_SHIFTLEFT:{
			printPureToken(token,"TKOPT_SHIFTLEFT");
			break;
		}
		case TKOPT_SHIFTRIGHT:{
			printPureToken(token,"TKOPT_SHIFTRIGHT");
			break;
		}
		case TKOPT_SHIFTLEFTASSIGN:{
			printPureToken(token,"TKOPT_SHIFTLEFTASSIGN");
			break;
		}
		case TKOPT_SHIFTRIGHTASSIGN:{
			printPureToken(token,"TKOPT_SHIFTRIGHTASSIGN");
			break;
		}
            //area
        case TKOPT_LEFTBLOCK:{
            printPureToken(token,"TKOPT_LEFTBLOCK");
            break;
        }
        case TKOPT_RIGHTBLOCK:{
            printPureToken(token,"TKOPT_RIGHTBLOCK");
            break;
        }
        case TKOPT_LEFTBRACKET:{
            printPureToken(token,"TKOPT_LEFTBRACKET");
            break;
        }
        case TKOPT_RIGHTBRACKET:{
            printPureToken(token,"TKOPT_RIGHTBRACKET");
            break;
        }
        case TKOPT_LEFTINDEX:{
            printPureToken(token,"TKOPT_LEFTINDEX");
            break;
        }
        case TKOPT_RIGHTINDEX:{
            printPureToken(token,"TKOPT_RIGHTINDEX");
            break;
        }
            //cmp
        case TKOPT_MORE:{
            printPureToken(token,"TKOPT_MORE");
            break;
        }
        case TKOPT_MORETHAN:{
            printPureToken(token,"TKOPT_MORETHAN");
            break;
        }
        case TKOPT_LESS:{
            printPureToken(token,"TKOPT_LESS");
            break;
        }
        case TKOPT_LESSTHAN:{
            printPureToken(token,"TKOPT_LESSTHAN");
            break;
        }
        case TKOPT_EQUAL:{
            printPureToken(token,"TKOPT_EQUAL");
            break;
        }
        case TKOPT_NOTEQUAL:{
            printPureToken(token,"TKOPT_NOTEQUAL");
            break;
        }
            //specail
        case TKOPT_TO:{
            printPureToken(token,"TKOPT_TO");
            break;
        }
        case TKOPT_AS:{
            printPureToken(token,"TKOPT_AS");
            break;
        }
            //grammar
        case TKOPT_END:{
            printPureToken(token,"TKOPT_END");
            break;
        }
        case TKOPT_COMMA:{
            printPureToken(token,"TKOPT_COMMA");
            break;
        }
        case TKOPT_DOT:{
            printPureToken(token,"TKOPT_DOT");
            break;
        }
        //keyword
        case TKKEY_DO:{
            printPureToken(token,"TKKEY_DO");
            break;
        }
        case TKKEY_IF:{
            printPureToken(token,"TKKEY_IF");
            break;
        }
        case TKKEY_ELSE:{
            printPureToken(token,"TKKEY_ELSE");
            break;
        }        
        case TKKEY_WHILE:{
            printPureToken(token,"TKKEY_WHILE");
            break;
        }
        case TKKEY_FOR:{
            printPureToken(token,"TKKEY_FOR");
            break;
        }
        case TKKEY_RETURN:{
            printPureToken(token,"TKKEY_RETURN");
            break;
        }
        case TKKEY_BREAK:{
            printPureToken(token,"TKKEY_BREAK");
            break;
        }
        case TKKEY_CONTINUE:{
            printPureToken(token,"TKKEY_CONTINUE");
            break;
        }
        case TKKEY_TRUE:{
            printPureToken(token,"TKKEY_TRUE");
            break;
        }
        case TKKEY_FALSE:{
            printPureToken(token,"TKKEY_FALSE");
            break;
        }
        case TKKEY_NAMESPACE:{
            printPureToken(token,"TKKEY_NAMESPACE");
            break;
        }
        case TKKEY_IMPORT:{
            printPureToken(token,"TKKEY_IMPORT");
            break;
        }
        case TKKEY_STRUCT:{
            printPureToken(token,"TKKEY_STRUCT");
            break;
        }
        case TKKEY_ENUM:{
            printPureToken(token,"TKKEY_ENUM");
            break;
        }
        case TKKEY_INTERFACE:{
            printPureToken(token,"TKKEY_INTERFACE");
            break;
        }

        case TKKEY_NEW:{
			printPureToken(token,"TKKEY_NEW");
            break;
        }
        case TKKEY_DELETE:{
            printPureToken(token,"TKKEY_DELETE");
            break;
        }
        case TKKEY_NULL:{
            printPureToken(token,"TKKEY_NULL");
            break;
        }
        case TKKEY_VOID:{
            printPureToken(token,"TKKEY_VOID");
            break;
        }
        case TKKEY_BOOL:{
            printPureToken(token,"TKKEY_BOOL");
            break;
        }
        case TKKEY_CHAR:{
            printPureToken(token,"TKKEY_CHAR");
            break;
        }
        case TKKEY_UCHAR:{
            printPureToken(token,"TKKEY_UCHAR");
            break;
        }
        case TKKEY_SHORT:{
            printPureToken(token,"TKKEY_SHORT");
            break;
        }
        case TKKEY_USHORT:{
            printPureToken(token,"TKKEY_USHORT");
            break;
        }
        case TKKEY_INT:{
            printPureToken(token,"TKKEY_INT");
            break;
        }
        case TKKEY_UINT:{
            printPureToken(token,"TKKEY_UINT");
            break;
        }
        case TKKEY_LONG:{
            printPureToken(token,"TKKEY_LONG");
            break;
        }
        case TKKEY_ULONG:{
            printPureToken(token,"TKKEY_ULONG");
            break;
        }
        case TKKEY_FLOAT:{
            printPureToken(token,"TKKEY_FLOAT");
            break;
        }
        case TKKEY_DOUBLE:{
            printPureToken(token,"TKKEY_DOUBLE");
            break;
        }

        default:{
            printf("TK_NONE:\tline:%d\tcolumn:%d\n",token->location.line,token->location.column);
        }
    }
}

Token *handleStringToken(Token *token)
{
	assert(token);
	if(token->text){
		char *p;
		int offset;
		offset=0;
		p=token->text;
		while((*p)!='\0'){
			if((*p)=='\\'){
				offset++;
				p++;
				switch(*p){
					case '0':{
						*(p-offset)=0;
						break;
					}
					case 'n':{
						*(p-offset)='\n';
						break;
					}
					case 'r':{
						*(p-offset)='\r';
						break;
					}
					case 't':{
						*(p-offset)='\t';
						break;
					}
					case 'a':{
						*(p-offset)='\a';
					}
					case 'b':{
						*(p-offset)='\b';
						break;
					}
					case 'v':{
						*(p-offset)='\v';
						break;
					}
					case 'f':{
						*(p-offset)='\f';
						break;
					}
					default: *(p-offset)=*p;
				}
			}else{
				if(offset>0){
					*(p-offset)=*p;
				}
			}
			p++;
		}
	}
	
	return token;
}